package cn.flying.cloud.gateway.fileter;

import javax.annotation.Resource;

import java.util.List;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.PathMatcher;
import org.springframework.web.server.ServerWebExchange;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import reactor.core.publisher.Mono;

import cn.flying.cloud.base.common.constants.Constants;
import cn.flying.cloud.base.common.utils.lang.ThreadLocalUtil;
import cn.flying.cloud.gateway.oauth.configuration.authentication.WhiteListConfig;

/**
 * 全局过滤器，将登录用户的Jwt转化成用户信息传递给下游
 *
 * @author: admin
 * @date: 2023年06月26日 10:27
 * @version: 1.0
 */
@Component
public class GlobalAuthTokenTransferGlobalFilter implements GlobalFilter, Ordered {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private WhiteListConfig whiteListConfig;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String traceId = UUID.randomUUID().toString().replaceAll("-", "");
        MDC.put(Constants.TRAC_ID, traceId);
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpRequest.Builder mutate = request.mutate();
        mutate.header(Constants.TRAC_ID, traceId);

        //获取请求的uri
        String path = request.getURI().getPath();
        logger.info("全局网关拦截请求uri：【{}】", path);

        //白名单跳过
        PathMatcher pathMatcher = new AntPathMatcher();
        List<String> uris = whiteListConfig.getUris();
        for (String uri : uris) {
            if (pathMatcher.match(uri, path)) {
                ServerHttpRequest info = mutate.build();
                return chain.filter(exchange.mutate().request(info).build());
            }
        }

        return ReactiveSecurityContextHolder.getContext()
                .map(SecurityContext::getAuthentication)
                .cast(JwtAuthenticationToken.class)
                .flatMap(authentication -> {
                    // 请求对象中获取认证主体
                    JSONObject principal = JSON.parseObject(JSON.toJSONString(authentication.getPrincipal(), JSONWriter.Feature.WriteMapNullValue));
                    JSONObject claims = (JSONObject) principal.get("claims");
                    JSONObject userInfo = (JSONObject) claims.get("userInfo");

                    ServerHttpRequest info = mutate
                            .header(Constants.TENANT_ID, userInfo.getString("tenantId"))
                            .header(Constants.USER_ID, userInfo.getString("userId"))
                            .header(Constants.USER_NAME, userInfo.getString("userName"))
                            .build();
                    // 从header取出参数set到当前线程
                    if (!CollectionUtils.isEmpty(info.getHeaders().get(Constants.REQUEST_ID))) {
                        ThreadLocalUtil.set(Constants.REQUEST_ID, info.getHeaders().get(Constants.REQUEST_ID).get(0));
                    }
                    if (!CollectionUtils.isEmpty(info.getHeaders().get(Constants.ENV_ID))) {
                        ThreadLocalUtil.set(Constants.ENV_ID, info.getHeaders().get(Constants.ENV_ID).get(0));
                    }
                    return chain.filter(exchange.mutate().request(info).build());
                });
    }

    @Override
    public int getOrder() {
        return 0;
    }
}